#include "KcPickSimilarPhoto.h"
#include <QImage>
#include <memory>

namespace kPrivate
{
    using feature_t = KcPickSimilarPhoto::feature_type;

    // 计算并返回图像@img的特征序列
    static feature_t calcFeature(const QImage* imgOrig)
    {
        auto img = imgOrig->scaled(16, 16, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); // 统一特征维度
        img = img.convertToFormat(QImage::Format_Grayscale8); // 转换到灰度图，色彩无关

        feature_t feat;
        feat.reserve(16 * 16);
        double maxclr(0);
        for (int i = 0; i < 16; i++)
            for (int j = 0; j < 16; j++) {
                auto clr = qRed(img.pixel(i, j));
                feat.push_back(clr);
                if (clr > maxclr)
                    maxclr = clr;
            }

        for (auto& v : feat)
            v /= maxclr; // 归一化， 图像明暗无关
        return feat;
    }

    // 计算特征@f1和@f2的相似度. 目前默认f1和f2已归一化，返回两者的欧几里得距离.
    static double calcSimilarity(const feature_t& f1, const feature_t& f2)
    {
        if (f1.size() != f2.size())
            return 0;

        double sum(0);
        for (int i = 0; i < f1.size(); i++)
            sum += (f1[i] - f2[i]) * (f1[i] - f2[i]);

        return 1. - std::sqrt(sum);
    }
}

void KcPickSimilarPhoto::doCalc_(const QString& filePath, void* fileObj)
{
    auto img = (QImage*)(fileObj);
    auto feat = kPrivate::calcFeature(img);

    for(auto& i : result_.keys()) {
        auto sim = kPrivate::calcSimilarity(feat, i);
        if (sim >= similarity_) { // 相似度达标，bingo
            auto& pos = result_[i];
            pos.first.append(filePath);
            if (pos.first.size() == 2) {
                // 补发信号
                pos.second = groupId_++;
                emit resultFound(pos.second, pos.first.front());
            }

            emit resultFound(pos.second, filePath);

            return;
        }
    }

    Q_ASSERT(!result_.contains(feat));
    result_[feat].first.append(filePath);
}

